package com.imooc.bilibili.support;

import com.imooc.bilibili.exception.ConditionException;
import com.imooc.bilibili.service.UserService;
import com.imooc.bilibili.util.TokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 用户相关支撑功能
 *
 * @author xiexu
 * @create 2022-06-15 09:39
 */
@Component
public class UserSupport {

    @Autowired
    private UserService userService;

    /**
     * 根据前端传过来的请求获取请求头中的token，从而获取用户id
     * 服务端将token传给前端之后，前端一般会把token保存在本地localstorage里面，
     * 下次前端在请求接口的时候，就会从localstorage拿到token，放在请求头中，
     * 这样子后端就可以根据前端传过来的请求头获取token
     *
     * @return
     */
    public Long getCurrentUserId() {
        // 获取前端请求
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        // 从前端请求的请求头里面获取访问token，进行解析
        HttpServletRequest request = requestAttributes.getRequest();
        String accessToken = request.getHeader("token");
        // 验证访问token，返回userId
        Long userId = TokenUtil.verifyToken(accessToken);
        if (userId < 0) {
            throw new ConditionException("非法用户！");
        }
        // 验证刷新token
        this.verifyRefreshToken(userId);
        return userId;
    }

    /**
     * 验证刷新token
     * 用户在退出之后就会删除数据库中的刷新token，如果这时用户还拿着有效期内的访问token来访问服务器，
     * 服务器会校验到前端请求的刷新token和数据库中的刷新token不一致，从而抛出异常。
     * 所以双token机制也就可以保证用户在退出之后，不能使用有效期内的访问token来继续访问服务器了
     *
     * @param userId
     */
    private void verifyRefreshToken(Long userId) {
        // 获取前端请求
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        // 从前端请求的请求头里面获取刷新token，进行解析
        HttpServletRequest request = requestAttributes.getRequest();
        String refreshToken = request.getHeader("refreshToken");
        // 根据用户id获取数据库中存储的刷新token
        String dbRefreshToken = userService.getRefreshTokenByUserId(userId);
        // 校验前端请求的刷新token 和 数据库中的刷新token是否一致
        if (!refreshToken.equals(dbRefreshToken)) {
            throw new ConditionException("非法用户！");
        }
    }

}
